package com.zijidelu.luframework.api.controller;

import com.zijidelu.luframework.api.model.ApiRequest;
import com.zijidelu.luframework.api.model.ApiResult;
import com.zijidelu.luframework.api.model.Request;
import com.zijidelu.luframework.api.model.Response;
import com.zijidelu.luframework.application.service.AppService;
import com.zijidelu.luframework.base.model.DataModel;
import com.zijidelu.luframework.base.exception.BizException;
import com.zijidelu.luframework.base.valid.BaseValid;
import com.zijidelu.luframework.infrastructure.model.api.PageQuery;
import com.zijidelu.luframework.infrastructure.model.api.PageResponse;
import org.springframework.validation.annotation.Validated;

/**
 * 读取控制器接口。
 *
 * @param <D> 数据模型类型
 * @author ZIJIDELU
 * @datetime 2025/11/8 17:36
 */
public interface ReaderController<D extends DataModel, R extends Response, Q extends Request> extends DataConversionSupport<D, R, Q> {
    AppService<D> getAppService();

    /**
     * 在根据ID查询数据之前调用。
     *
     * @param id 数据ID
     */
    default void beforeFindById(ApiRequest<Long> id) {
        if (id == null || id.getPayload() == null) {
            throw new BizException("id 为必填项");
        }
    }

    /**
     * 根据ID查询数据。
     *
     * @param id 数据ID
     * @return 数据响应
     */
    default ApiResult<R> findById(@Validated({BaseValid.class}) ApiRequest<Long> id) {
        beforeFindById(id);

        final D data = getAppService().findById(id.getPayload());
        final R response = getDataResponseConverter().dtoToResponse(data);

        afterFindById(data);
        return ApiResult.successOf(response);
    }

    /**
     * 在根据ID查询数据之后调用。
     *
     * @param data 查询到的数据
     */
    default void afterFindById(D data) {
    }

    /**
     * 在查询数据分页列表之前调用。
     *
     * @param query 分页查询参数
     */
    default void beforeFindPage(ApiRequest<PageQuery<Q>> query) {
        if (query == null || query.getPayload() == null) {
            throw new BizException("分页查询参数为必填项");
        }
    }

    /**
     * 查询数据分页列表。
     *
     * @param query 分页查询参数
     * @return 分页数据响应
     */
    default ApiResult<PageResponse<R>> findPage(@Validated({BaseValid.class}) ApiRequest<PageQuery<Q>> query) {
        beforeFindPage(query);

        final D data = getDataRequestConverter().requestToDto(query.getPayload().getData());
        final PageQuery<D> dPageQuery = query.getPayload().copyWith(data);
        final PageResponse<R> pageResponse = getAppService().findPage(dPageQuery)
                .convertRecords(getDataResponseConverter()::dtoToResponse);

        afterFindPage(pageResponse);
        return ApiResult.successOf(pageResponse);
    }

    /**
     * 在查询数据分页列表之后调用。
     *
     * @param pageResponse 分页数据响应
     */
    default void afterFindPage(PageResponse<R> pageResponse) {
    }

}
